You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds the “Instance Boot Group” feature (per design spec) across the CloudStack stack, including new API surface, persistence schema, readiness evaluation/checkers, and UI flows to manage members, boot order, and readiness rules.
Changes:
Introduces Instance Boot Group core entities (DB tables/views + VO/DAO/query-join) and API commands/responses for CRUD, membership, start/stop/reboot sequencing, and readiness rules.
Adds readiness rule execution plumbing (VR-dispatched ping/port checks, KVM guest-agent liveness command/wrapper) and Spring wiring/registries for checker strategy discovery.
Adds UI navigation and screens for boot groups (listing/details/members, add/remove members, update boot order, manage/view readiness rules) plus i18n strings and icon wiring.
Reviewed changes
Copilot reviewed 82 out of 83 changed files in this pull request and generated 3 comments.
VerticalAlignMiddleOutlined is registered twice on the Vue app, which is redundant and can mask issues when refactoring the icon list. Remove the duplicate component registration.
❌ Patch coverage is 81.65070% with 498 lines in your changes missing coverage. Please review.
✅ Project coverage is 20.21%. Comparing base (1a48a87) to head (3ee23da).
a-form's @finish handler is invoked with form values (not a DOM event). As written, handleSubmit will throw when called from @finish because e.preventDefault() is executed on a non-event/undefined. Make handleSubmit tolerant of non-event invocations (e.g., only call preventDefault when present) or split into separate submit handlers for click vs. finish. ui/src/views/compute/UpdateInstanceBootGroupMemberOrder.vue:1
a-form's @finish handler is invoked with form values (not a DOM event). As written, handleSubmit will throw when called from @finish because e.preventDefault() is executed on a non-event/undefined. Make handleSubmit tolerant of non-event invocations (e.g., only call preventDefault when present) or split into separate submit handlers for click vs. finish. ui/src/views/compute/AddInstanceBootGroupMember.vue:1
Same issue as the update-order modal: @finish passes form values, not a DOM event, so e.preventDefault() can throw and break submission. Update handleSubmit to safely handle calls from both @finish and button/keyboard events. ui/src/views/compute/AddInstanceBootGroupMember.vue:1
Same issue as the update-order modal: @finish passes form values, not a DOM event, so e.preventDefault() can throw and break submission. Update handleSubmit to safely handle calls from both @finish and button/keyboard events. ui/src/views/compute/AddInstanceBootGroupMember.vue:1
The form currently only validates order, so it’s possible to submit without selecting a VM/InstanceGroup, relying on backend errors. Add client-side required validation for virtualmachineid when membertype is VirtualMachine, and for instancegroupid when membertype is InstanceGroup (and consider clearing validation errors when toggling member type). ui/src/views/compute/AddInstanceBootGroupMember.vue:1
The form currently only validates order, so it’s possible to submit without selecting a VM/InstanceGroup, relying on backend errors. Add client-side required validation for virtualmachineid when membertype is VirtualMachine, and for instancegroupid when membertype is InstanceGroup (and consider clearing validation errors when toggling member type). ui/src/views/compute/AddInstanceBootGroupMember.vue:1
The form currently only validates order, so it’s possible to submit without selecting a VM/InstanceGroup, relying on backend errors. Add client-side required validation for virtualmachineid when membertype is VirtualMachine, and for instancegroupid when membertype is InstanceGroup (and consider clearing validation errors when toggling member type). core/src/main/java/com/cloud/agent/resource/virtualnetwork/VirtualRoutingResource.java:1
This handler hard-codes _eachTimeout to 60 seconds and ignores the wait set on the command (cmd.setWait(...) is used by the callers to respect an attempt budget). This can cause attempts to exceed the intended budget or time out too early. Use the command’s wait value (or derive _eachTimeout from it) instead of a fixed constant. server/src/main/java/org/apache/cloudstack/vm/bootgroup/readiness/VrPingChecker.java:1
The code casts Answer to InstanceReadinessCheckAnswer without verifying the type or checking answer.getResult(). In mixed-version/upgrade scenarios or when the VR can’t execute the script, the agent may return a different Answer type or a failure response, leading to ClassCastException and breaking readiness evaluation. Guard with instanceof, handle !answer.getResult() explicitly, and surface answer.getDetails() as the error message. server/src/main/java/org/apache/cloudstack/vm/bootgroup/readiness/PortCheckChecker.java:1
Same unsafe cast pattern as VrPingChecker: Answer is cast to InstanceReadinessCheckAnswer without instanceof/getResult() checks. This can crash the checker and abort readiness computation. Add defensive checks and handle failed answers by returning Status.Error with the agent-provided details. engine/schema/src/main/java/com/cloud/vm/dao/InstanceBootGroupReadinessCheckResultDaoImpl.java:1
This upsert is not atomic: concurrent writers can both observe existing == null and then attempt persist, violating the unique key on (rule_id, vm_id) and causing intermittent failures under parallel readiness evaluation. Wrap this in a transaction with appropriate locking, or implement a DB-level upsert pattern (e.g., try-insert then update on duplicate) so concurrent updates are safe. core/src/main/java/org/apache/cloudstack/vm/bootgroup/readiness/InstanceReadinessCheckAnswer.java:1
The answer parsing relies on a string delimiter (&&) and throws a runtime exception if the format isn't exactly as expected. Any unexpected script output (including delimiter collisions) will bubble up as an exception and can disrupt readiness evaluation. Consider switching the VR script to emit structured output (e.g., JSON with stdout/stderr/exitcode fields) and make the parser fail-soft (returning exitcode=-1 with a descriptive stderr) rather than throwing.
InstanceReadinessCheckCommand.setWait(...) is computed from the remaining budget, but this handler hardcodes _eachTimeout to 60s. This makes the command’s per-attempt wait budget ineffective (the VR script execution timeout can exceed the intended budget). plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckGuestAgentLivenessCommandWrapper.java:74
The wrapper uses a fixed 5s timeout for qemuAgentCommand(...) and ignores command.getWait(), even though the caller sets the command wait from the remaining readiness budget. This can cause false negatives when the readiness attempt budget is higher than 5s. server/src/main/java/org/apache/cloudstack/vm/bootgroup/InstanceBootGroupMembershipGuard.java:99
validateVmEligibleForGroupMembership only checks the first Instance Group mapping for the VM (currentMappings.get(0)). Since instance_group_vm_map does not enforce one-group-per-VM, a VM can be in multiple instance groups, and this can miss a disqualifying group that is already a boot-group member.
The form validation only enforces order, so it’s possible to submit without selecting a VM/instance group, which will send an API request missing the required virtualmachineid/instancegroupid parameter.
The reason will be displayed to describe this comment to others. Learn more.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
This read-then-insert upsert is not atomic despite the unique (rule_id, vm_id) key. Two concurrent boot-group starts (or a readiness evaluation racing with restart invalidation) can both observe no row and then one persist fails with a duplicate-key exception, aborting readiness instead of updating the existing result. Use an atomic database upsert or serialize/lock the key before inserting.
ControlledViewEntity.getEntityType() must identify the domain resource represented by the view, but this returns the join-VO class itself. InstanceGroupJoinVO follows the required pattern and returns InstanceGroup.class (server/src/main/java/com/cloud/api/query/vo/InstanceGroupJoinVO.java:165-168); returning InstanceBootGroupJoinVO.class can break resource-type handling for ACL/response metadata. Return the InstanceBootGroup domain type instead.
Soft-deleting boot groups leaves orphaned readiness data
Deleting a boot group only removes its member rows and soft-deletes the group. The readiness rules, rule details, cached results, and group details are therefore left behind: these ON DELETE CASCADE constraints do not run for a soft delete. Clean up the associated readiness/detail rows in the delete transaction (or explicitly expunge the group) so deleted groups cannot leave active orphaned rules and unbounded cache data.
Inherited rules bypass pagination for VM-filtered listings
When listing by virtualmachineid, inherited rules are appended after the DAO has already applied startIndex/pageSize to direct rules. As a result, every page repeats all inherited rules, responses can exceed the requested page size, and the returned count does not describe the page contents consistently. Combine direct and inherited rules before applying pagination, or paginate the inherited portion separately.
Enter submission handler calls preventDefault on form values
When the form is submitted with Enter, Ant Design Vue invokes @finish with the form values object, not a DOM event. That object has no preventDefault(), so this handler throws before validation and keyboard submission cannot update the member order. Guard the event call or separate the click and finish handlers.
@shwstppr a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Feature to add the concept of instance boot group and readiness rules.
Design spec: https://cwiki.apache.org/confluence/spaces/CLOUDSTACK/pages/449282465/Instance+Boot+Group+and+Readiness+Rules
Documentation PR: apache/cloudstack-documentation#677
Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
Screenshots (if appropriate):
How Has This Been Tested?
How did you try to break this feature and the system with this change?